package ChessEngine.moveGenerator;

import ChessEngine.PieceSquareTableEvaluator;
import ChessEngine.moveGenerator.Exceptions.BoardException;
import Pieces.*;
import boardData.*;
import java.util.LinkedList;


/**
 * Klasse welche die moeglichen zuege generiert, die auf dem momentanen Brett
 * moeglich sind.
 * 
 * @author Thomas Rausch
 * @version V1.b.0 (28.09.'11)
 * 
 */
public class MoveGenerator {

	private static final int ONE_FIELD_LEFT  = -1;
	private static final int ONE_FIELD_RIGHT = 1;
	private static final int ONE_FIELD_AHEAD  = 10;
	private static final int ONE_FIELD_BACK = -10;
	
	private LinkedList<Board> movelist;
	private LinkedList<Integer> pawnlist ;
	private boolean color; //true = weiß /false = black
	
	
	//Figuren
	private int emptyField= PieceValues.EMPTY_FIELD;
	private int illegalField= PieceValues.ILLEGAL_FIELD;
	
	private int whitePawn= PieceValues.WHITE_PAWN;
	private int whiteKnight= PieceValues.WHITE_KNIGHT;
	private int whiteKing = PieceValues.WHITE_KING;
	private int whiteBishop = PieceValues.WHITE_BISHOP;
	private int whiteRook = PieceValues.WHITE_ROOK;
	private int whiteQueen = PieceValues.WHITE_QUEEN;
	
	private int blackPawn= PieceValues.BLACK_PAWN;
	private int blackKnight= PieceValues.BLACK_KNIGHT;
	private int blackKing = PieceValues.BLACK_KING;
	private int blackBishop = PieceValues.BLACK_BISHOP;
	private int blackRook = PieceValues.BLACK_ROOK;
	private int blackQueen = PieceValues.BLACK_QUEEN;
	
//------------------------------Extern aufrufbare Methoden-----------------------------
	
	
	/**
	 * Standart Construktor des MoveGenrators
	 */
	public MoveGenerator() {
	}
	
	/**
	 * Von aussen aufrufbare Methode , welche die momentan moeglichen zuege fuer das
	 * mitgelieferte Brett und die angegebene Farbe in einer Verketteten Liste
	 * von Boards zurueckliefert.
	 * 
	 * @param board
	 *            Momentanes Spielbrett von welchem ausgehend berechnet werden
	 *            soll.
	 * @param white
	 *            Die Farbe fuer die die zuege berechnet werden sollen.
	 *            fuer Weiss true,
	 *            fuer schwarz false.
	 *            
	 * @return Eine Verketteteliste welsche die boards mit den moeglichen zuegen beinhaltet.
	 * 		   Falls kein zug moeglich ist, ist die liste leer.
	 * 
	 * @throws BoardException 
	 * 			  falls das uebergebene Board null ist.	
	 */
	public LinkedList<Board> generateMove(Board board, boolean white) throws BoardException  {
		initializeGenerator(board,white);
		scanBoard(board,color);
		return movelist;
	}
	
	/**Ueberprueft ein feld ob es bedroht wird.
	 * @param board das zu ueberpruefende Brett.
	 * @param field das Feld welches ueberprueft werden soll.
	 * @return true wenn das uebergebene Feld auf dem uebergebenen Board bedroht ist. 
	 * 		   false wenn nicht.
	 */
	public boolean isThreatens(Board board,int field,boolean color){
		return isCheck(board, color, true, field);
		
	}
	/** Gibt die Position des Königs auf dem übergebenen Board aus.
	 * @param board Board auf dem der König gesucht werden soll.
	 * @param colour farbe des zu suchenden Königs true= weiß false= schwarz.
	 * @return position des Königs als int.
	 */
	public int whereIsTheKing(Board board, boolean colour){
		int king=PieceValues.ILLEGAL_FIELD;
		if (colour) {
			king=PieceValues.WHITE_KING;
		}		
		if (!colour) {
			king=PieceValues.BLACK_KING;
		}	
		return findKing(board, king);
	}
//--------------------------Initialisierungsblock-------------------------------------------------
	/**Diese Methode initialisiert den ZugGenerator
	  * @param board
	  * 		  Momentanes Spielbrett von welchem ausgehend berechnet werden
	 *            soll.
	 * @param white
	 *            Die Farbe fuer die die zuege berechnet werden sollen.
	 *            fuer Weiss true,
	 *            fuer schwarz false.
	 * @throws BoardException
	 */
	private void initializeGenerator(Board board, boolean white) throws BoardException {
		pawnlist = new LinkedList<Integer>();
		movelist = new LinkedList<Board>();
		this.color=white;
		BoardException.ifBoardEmpty(board);
		generatePawnList(color,board);
		
	}
	/**Generiert eine Liste der Bauern, welche noch einen Doppelzug machen duerfen.
	 * 
	 * @param white Farbe für die die Bauernliste erstellt werden soll.
	 * @param board Brett welches zur erstellung heran gezogen werden soll.
	 */
	private void generatePawnList(boolean white,Board board) {
		if (white) {
			for (int position = 81; position <= (88); position++) {
				if (board.getPiece(position)==whitePawn) {
					pawnlist.add(position);
				}				
			}			
		} 
		if (!white) {
			for (int position = 31; position <= (38); position++) {
				if (board.getPiece(position)==blackPawn) {
					pawnlist.add(position);
				}
			}
		}
		
	}
	//-------------------------------------Moegliche Boards berechnen--------------------------
	/**
	 * Diese Methode durchlauuft das ganze Board,und ruft die entsprechende movefunktion der gefundenen Figuren auf.
	 * 
	 * @param board
	 *            Das Spielbrett welches durchlaufen werden soll.
	 */
	private void scanBoard(Board board,boolean white) {
		
		
		int figureValue;
		
		boolean surveyCheck=false;
		boolean colour= false;
		
		if (white) {
			
		
		
		for (int currentPosition = 100; currentPosition >= (21); currentPosition--) {
			figureValue=board.getPiece(currentPosition);
			if (figureValue != emptyField) {
					
				if (figureValue == whitePawn) {
					moveWhitePawn(currentPosition, board);	
				}	
				if (figureValue == whiteRook) {
					moveRook(currentPosition, board,surveyCheck,colour);
				}
				if (figureValue == whiteKnight) {
					moveKnight(board, currentPosition, surveyCheck,colour);
				}
				
				if (figureValue == whiteBishop) {
					moveBishop(currentPosition, board,surveyCheck,colour);
				}
				
				if (figureValue == whiteQueen) {
					moveQueen(board, currentPosition,surveyCheck,colour);
				}
				if (figureValue == whiteKing) {
					moveKing(board, currentPosition, surveyCheck,colour);
				}
			}
			}			 						
	
		}
		if (!white) {
				
		for (int currentPosition = 100; currentPosition >= (21); currentPosition--) {
			figureValue=board.getPiece(currentPosition);
			
				if (figureValue == blackPawn) {
					moveBlackPawn(currentPosition, board);	
				}	
				if (figureValue == blackRook) {
					moveRook(currentPosition, board,surveyCheck,colour);
				}
				if (figureValue == blackKnight) {
					moveKnight(board, currentPosition, surveyCheck,colour);
				}
				
				if (figureValue == blackBishop) {
					moveBishop(currentPosition, board,surveyCheck,colour);
				}
				
				if (figureValue == blackQueen) {
					moveQueen(board, currentPosition,surveyCheck,colour);
				}
				if (figureValue == blackKing) {
					moveKing(board, currentPosition, surveyCheck,colour);
				}
			
			}			 						
	
		}
			
		
		}
	
	
	/**
	 * Diese Funktion haengt die konstruierten Boards mit den moeglichen
	 * Spielzuegen in eine Verkettete Liste ein.
	 * 
	 * @param board
	 *            Spielbrett, welches in die Liste eingehaengt werden soll.
	 */
	private void createBoardObject(Board board) {
	// Vor dem einhaengen in die Liste wird jedes Brett ueberprueft ob der Koenig im Schach steht.
		//ist dies der Fall wird das Board verworfen.
		//Steht der Koenig nicht im Schach wird das Board in die Liste gehaengt.
			
			if (!isCheck(board, color,false,illegalField)) {
				movelist.add(board);
			}
	}
	//--------------------------Move Funktionen----------------------------------------------
	
	/**
	 * Diese Funktion berechnet die moeglichen zuege fuer einen Weissen Bauern, auf dem
	 * mitgegebenen Spielbrett unter der angegebenen Position.
	 * 
	 * @param currentPosition
	 *            Position auf der sich der Bauer befindet,fuer den die moeglichen
	 *            Zuege ermittelt werden sollen.
	 * @param board
	 *            Spielbrett auf dem der Bauer steht.
	 */
	private void moveWhitePawn(int currentPosition, Board board) {
		int possiblePossition=currentPosition;
		if (isDoubleMovePossible(currentPosition)) {

			if ((isEmptyField(board, currentPosition - 20))
					&&(isEmptyField(board, currentPosition - 10))){
				
				createBoardObject(board.moveClone(currentPosition,
						(currentPosition - 20)));
			}
		}

			for (int i = 9; i <= 11; i++) {
				possiblePossition-=i;
				// evt. Ueberpruefung auf illegal_field ueberfluessig
				if (!isIllegalField(board,possiblePossition)) {
					if ((isEmptyField(board, possiblePossition ) && (i == 10))
							||(!isEmptyField(board, possiblePossition )&&
									isEnemy(board,currentPosition,possiblePossition) && (i != 10))
									||(possiblePossition == board.getEnPassant()&& (i != 10))) {
						if ((possiblePossition)/10==2) {
							pawnPromotion(board, currentPosition, -i);
						}else{
						createBoardObject(board.moveClone(currentPosition,(possiblePossition)));
						}
					}
				
				}
			possiblePossition=currentPosition;
			}		
		
	}
	/** Methode, welche die Bauern umwandlung von der Farbe unabhaengig vollzieht.
	 * 
	 * @param board Board auf dem der Umzuwandelnde Bauer steht.
	 * @param currentPosition Position des umzuwandelnden Bauers auf dem uebermittelten Board
	 * @param step Variable, welche die richtung enthaellt, in die sich der Bauer 
	 * 				bewegen muss um umgewandelt zu werden. Wichtig fuer die Farb unabhaengigkeit der Methode.
	 */
	private void pawnPromotion (Board board, int currentPosition,int step ){
		createBoardObject(board.moveClone(currentPosition,(currentPosition+step),'q'));//X_QUEEN
		createBoardObject(board.moveClone(currentPosition,(currentPosition+step),'b'));//X_BISHOP
		createBoardObject(board.moveClone(currentPosition,(currentPosition+step),'r'));//X_ROOK
		createBoardObject(board.moveClone(currentPosition,(currentPosition+step),'n'));//X_KNIGHT
	}
	/**
	 * Diese Funktion berechnet die moeglichen zuege fuer einen Schwarzen Bauern, auf dem
	 * mitgegebenen Spielbrett unter der angegebenen Position.
	 * 
	 * @param currentPosition
	 *            Position auf der sich der Bauer befindet, fuer den die moeglichen
	 *            Zuege ermittelt werden sollen.
	 * @param board
	 *            Spielbrett auf dem der Bauer steht.
	 */
	private void moveBlackPawn(int currentPosition, Board board) {
		
		int possiblePossition=currentPosition;
		if (isDoubleMovePossible(currentPosition)) {

			if ((isEmptyField(board, currentPosition + 20))
					&&(isEmptyField(board, currentPosition + 10))){
				
				createBoardObject(board.moveClone(currentPosition,
						(currentPosition + 20)));
			}
		

		}
			for (int i = 9; i <= 11; i++) {
				possiblePossition+=i;
				// evt. Ueberpruefung auf illegal_field ueberfluessig
				if (!isIllegalField(board,possiblePossition)) {		
					if ((isEmptyField(board, possiblePossition ) && (i == 10))
							||(isEnemy(board,currentPosition,possiblePossition) && (i != 10)) 
							||(possiblePossition == board.getEnPassant()&& (i != 10))) {
						if ((possiblePossition)/10==9) {
							pawnPromotion(board, currentPosition, i);
						}else{
						createBoardObject(board.moveClone(currentPosition,(currentPosition + i)));
						}
					}
				
				}
				possiblePossition=currentPosition;
			}
	}
	// Ja wie macht das Pferdschen ? Hüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüü!!!!
	
	/**
	 * Diese Funktion berechnet die moeglichen zuege fuer ein Pferd, auf dem
	 * mitgegebenen Spielbrett unter der angegebenen Position.
	 * 
	 * * @param board
	 *            Spielbrett auf dem das Pferd steht.
	 *            
	 * @param currentPosition
	 *            Position auf der sich das Pferd befindet fuer das die moeglichen
	 *            Zuege ermittelt werden sollen.
	 *            
	 * @param surveyCheck wenn true, soll nur ueberprueft werde, ob currentPosition ein bedrohtes Feld ist, ohne Boards zu erstellen.
	 * 					  wenn false, sollen neue Zugmoeglichkeiten ermittelt werden.	 
	 * @param colour  Farbe, fuer die die Zugmoeglichkeiten ermittelt werden sollen.
	 * 
	 * @return wenn surveyCheck true ist: true wenn currentPosition bedroht ist.
	 * 									   false wenn currentPosition nicht bedroht ist.
	 * 		   wenn surveyCheck false ist: immer false.		
	 */
	private boolean moveKnight(Board board,int currentPosition,  boolean surveyCheck,boolean colour ) {
		int figure=PieceValues.ILLEGAL_FIELD;
		if (surveyCheck) {
			if (board.giveColour(currentPosition)) {
				figure=PieceValues.WHITE_KNIGHT;
			}
			if (!board.giveColour(currentPosition)) {
				figure=PieceValues.BLACK_KNIGHT;
			}
		}
		
		if (singleMove(board, currentPosition, ((2*ONE_FIELD_RIGHT)+ONE_FIELD_AHEAD),surveyCheck,figure) && surveyCheck) {
	
			return true;
		}
		if (singleMove(board,currentPosition,((2*ONE_FIELD_AHEAD)+ONE_FIELD_LEFT),surveyCheck,figure)&& surveyCheck) {
	
			return true;
		}
		if (singleMove(board, currentPosition, ((2*ONE_FIELD_LEFT)+ONE_FIELD_BACK),surveyCheck,figure) && surveyCheck) {

			return true;
		}
		if (singleMove(board, currentPosition, ((2*ONE_FIELD_RIGHT)+ONE_FIELD_BACK),surveyCheck,figure) && surveyCheck) {
	
			return true;
		}
		
		if (singleMove(board, currentPosition, ((2*ONE_FIELD_AHEAD)+ONE_FIELD_RIGHT),surveyCheck,figure) && surveyCheck) {

			return true;
		}
		if (singleMove(board, currentPosition, ((2*ONE_FIELD_LEFT)+ONE_FIELD_AHEAD),surveyCheck,figure)&& surveyCheck) {
	
			return true;
		}
		if (singleMove(board, currentPosition, ((2*ONE_FIELD_BACK)+ONE_FIELD_LEFT),surveyCheck,figure) && surveyCheck) {
	
			return true;
		}
		if (singleMove(board, currentPosition, ((2*ONE_FIELD_BACK)+ONE_FIELD_RIGHT),surveyCheck,figure) && surveyCheck) {
		
			return true;
		}
					
		return false;

	}
	
	/**
	 * Diese Funktion berechnet die moeglichen zuege fuer den Koenig, auf dem
	 * mitgegebenen Spielbrett unter der angegebenen Position.
	 * 
	 * * @param board
	 *            Spielbrett auf dem der Koenig steht.
	 *
	 * @param currentPosition
	 *            Position auf der sich der Koenig befindet fuer den die moeglichen
	 *            Zuege ermittelt werden sollen.
	 *            
	  *            
	 * @param surveyCheck wenn true, soll nur ueberprueft werde, ob currentPosition ein bedrohtes Feld ist, ohne Boards zu erstellen.
	 * 					  wenn false, sollen neue Zugmoeglichkeiten ermittelt werden.	 
	 * @param colour  Farbe, fuer die die Zugmoeglichkeiten ermittelt werden sollen.
	 * 
	 * @return wenn surveyCheck true ist: true wenn currentPosition bedroht ist.
	 * 									   false wenn currentPosition nicht bedroht ist.
	 * 		   wenn surveyCheck false ist: immer false.		
	 */
	
	private boolean moveKing( Board board,int currentPosition,boolean surveyCheck,boolean colour) {
		int possiblePosition=currentPosition;
		boolean check=false;
		
		int king=PieceValues.ILLEGAL_FIELD;
		
		if (surveyCheck && colour) {
			king=PieceValues.WHITE_KING;
		}		
		if (surveyCheck && !colour) {
			king=PieceValues.BLACK_KING;
		}
		//Ueberprueft ob die kleine Rochade(kingside) moeglich ist.
		if (!surveyCheck&&isCastKingSide(currentPosition, board)) {	
			//pruefen ob könig vor der Rochade schon im Schach steht.
			if (!isCheck(board,board.giveColour(currentPosition),false,illegalField)) {
				//pruefen ob der König waehrend der Rochade im Schach steht
				//f1 pruefen
				possiblePosition+=ONE_FIELD_RIGHT;
				if (!isCheck(board.moveClone(currentPosition,possiblePosition),board.giveColour(currentPosition),false,illegalField)) {
					//g1 pruefen
					possiblePosition+=ONE_FIELD_RIGHT;
					//pruefen ob der Koenig nach der Rochade im Schach steht
					if (!isCheck(board.moveClone(currentPosition,possiblePosition),board.giveColour(currentPosition),false,illegalField)) {
						//kleine rochade ist moeglich, da der Koenig werder vor, waerend noch nach der Rochade im Schach steht
						createBoardObject(board.moveClone(currentPosition,possiblePosition));
					}
				}
				//naechste moegliche position zurueck setzen
				possiblePosition=currentPosition;	
			}
		}
		//Ueberprueft ob die große Rochade(queenside) moeglich ist.
		if (!surveyCheck&&isCastQueenSide(currentPosition, board)) {
			//pruefen ob könig vor der Rochade schon im Schach steht.
			if (!isCheck(board,board.giveColour(currentPosition),false,illegalField)) {
				//pruefen ob der König waehrend der Rochade im Schach steht
				//d1 pruefen
				possiblePosition+=ONE_FIELD_LEFT;
				if (!isCheck(board.moveClone(currentPosition,possiblePosition),board.giveColour(currentPosition),false,illegalField)) {
					//c1 pruefen
					possiblePosition+=ONE_FIELD_LEFT;
					//pruefen ob der Koenig nach der Rochade im Schach steht
					if (!isCheck(board.moveClone(currentPosition,possiblePosition),board.giveColour(currentPosition),false,illegalField)) {
						//große rochade ist moeglich, da der Koenig werder vor, waerend noch nach der Rochade im Schach steht
						createBoardObject(board.moveClone(currentPosition,possiblePosition));
					}
				}
				//naechste moegliche position zurueck setzen
				possiblePosition=currentPosition;			
			}
		}
		
		for (int i = 9; i <= 11; i++) {
			//grade aus links und rechts diagonal nach vorne!
			possiblePosition=currentPosition+i;
			if (!isIllegalField(board, possiblePosition)) {
				if (isEnemy(board, currentPosition, possiblePosition )
						|| isEmptyField(board, possiblePosition )) {
					
					if (surveyCheck) {
						if (isSpecialEnemy(board, king, possiblePosition)) {
							
							return check=true;
						}
					}else{
						
							createBoardObject(board.moveClone(currentPosition,(possiblePosition)));
						
					}
				}
			}
			//nachhinten  links und rechts diagonal nachhinten!
			possiblePosition=currentPosition-i;
			if (!isIllegalField(board, possiblePosition)) {
				if (isEnemy(board, currentPosition, possiblePosition )
						|| isEmptyField(board, possiblePosition )) {
					
					if (surveyCheck) {
						if (isSpecialEnemy(board, king, possiblePosition)) {
							return check=true;
						}
					}else{
						
							createBoardObject(board.moveClone(currentPosition,(possiblePosition)));
							
					}
					
				}
			}
		}
		if (singleMove(board, currentPosition, ONE_FIELD_LEFT,surveyCheck,king) && surveyCheck) {
	
			return true;
		}
		if (singleMove(board, currentPosition, ONE_FIELD_RIGHT,surveyCheck,king) && surveyCheck) {
	
			return true;
		}
		return check;
	}
	
	/**
	 * Diese Funktion berechnet die moeglichen zuege fuer einen Laeufer, auf dem
	 * mitgegebenen Spielbrett unter der angegebenen Position.
	 * 
	 * @param currentPosition
	 *            Position auf der sich der Laeufer befindet fuer den die
	 *            moeglichen Zuege ermittelt werden sollen.
	 * @param board
	 *            Spielbrett auf dem der Laeufer steht.
	  *            
	 * @param surveyCheck wenn true, soll nur ueberprueft werde, ob currentPosition ein bedrohtes Feld ist, ohne Boards zu erstellen.
	 * 					  wenn false, sollen neue Zugmoeglichkeiten ermittelt werden.	 
	 * @param colour  Farbe, fuer die die Zugmoeglichkeiten ermittelt werden sollen.
	 * 
	 * @return wenn surveyCheck true ist: true wenn currentPosition bedroht ist.
	 * 									   false wenn currentPosition nicht bedroht ist.
	 * 		   wenn surveyCheck false ist: immer false.		
	 */

	private boolean moveBishop(int currentPosition, Board board, boolean surveyCheck,boolean colour ) {
		if (multiMove(board, currentPosition, ONE_FIELD_AHEAD+ONE_FIELD_RIGHT,surveyCheck) && surveyCheck) {

			return true;
		}
		if (multiMove(board, currentPosition, ONE_FIELD_AHEAD+ONE_FIELD_LEFT,surveyCheck) && surveyCheck) {

			return true;
		}
		if (multiMove(board, currentPosition, ONE_FIELD_BACK+ONE_FIELD_RIGHT,surveyCheck) && surveyCheck) {

			return true;
		}
		if (multiMove(board, currentPosition, ONE_FIELD_BACK+ONE_FIELD_LEFT,surveyCheck) && surveyCheck) {

			return true;
		}
		return false;
		
	}
	
	/**
	 * Diese Funktion berechnet die mueglichen zuege fuer einen Turm, auf dem
	 * mitgegebenen Spielbrett unter der angegebenen Position.
	 * 
	 * @param currentPosition
	 *            Position auf der sich der Turm befindet fuer den die moeglichen
	 *            Zuege ermittelt werden sollen.
	 * @param board
	 *            Spielbrett auf dem der Turm steht.
	  *            
	 * @param surveyCheck wenn true, soll nur ueberprueft werde, ob currentPosition ein bedrohtes Feld ist, ohne Boards zu erstellen.
	 * 					  wenn false, sollen neue Zugmoeglichkeiten ermittelt werden.	 
	 * @param colour  Farbe, fuer die die Zugmoeglichkeiten ermittelt werden sollen.
	 * 
	 * @return wenn surveyCheck true ist: true wenn currentPosition bedroht ist.
	 * 									   false wenn currentPosition nicht bedroht ist.
	 * 		   wenn surveyCheck false ist: immer false.		
	 */
	
	private boolean moveRook(int currentPosition, Board board, boolean surveyCheck,boolean colour) {

		if (multiMove(board, currentPosition, ONE_FIELD_AHEAD,surveyCheck) && surveyCheck) {

			return true;
		}
		if (multiMove(board, currentPosition, ONE_FIELD_BACK,surveyCheck) && surveyCheck) {

			return true;
		}
		if (multiMove(board, currentPosition, ONE_FIELD_LEFT,surveyCheck) && surveyCheck) {

			return true;
		}
		if (multiMove(board, currentPosition, ONE_FIELD_RIGHT,surveyCheck) && surveyCheck) {

			return true;
		}
		
		return false;
	}
	/**
	 * Diese Funktion berechnet die moeglichen zuege fuer die Dame, auf dem
	 * mitgegebenen Spielbrett unter der angegebenen Position.
	 * 
	 * @param currentPosition
	 *            Position auf der sich die Dame befindet fuer die die moeglichen
	 *            Zuege ermittelt werden sollen.
	 * @param board
	 *            Spielbrett auf dem die Dame steht.
	 *                      
	 * @param surveyCheck wenn true, soll nur ueberprueft werde, ob currentPosition ein bedrohtes Feld ist, ohne Boards zu erstellen.
	 * 					  wenn false, sollen neue Zugmoeglichkeiten ermittelt werden.	 
	 * @param colour  Farbe, fuer die die Zugmoeglichkeiten ermittelt werden sollen.
	 * 
	 * @return wenn surveyCheck true ist: true wenn currentPosition bedroht ist.
	 * 									   false wenn currentPosition nicht bedroht ist.
	 * 		   wenn surveyCheck false ist: immer false.		
	 */
	
	private boolean moveQueen(Board board ,int currentPosition , boolean surveyCheck,boolean colour) {
		// Turm bewegung der Dame
		if (moveRook(currentPosition, board,surveyCheck,colour) && surveyCheck) {

			return true;
		}
		
		//LÃ¤ufer bewegung der Dame
		if (moveBishop(currentPosition, board,surveyCheck,colour) && surveyCheck) {

			return true;
		}
	
		
		return false;
	}
	/**
	 * Diese Funktion berechnet, ob ein Zug um die schrittlaenge step auf dem
	 * mitgegebenen Spielbrett unter der angegebenen Position moeglich ist.
	 * 
	 * @param board
	 *            Spielbrett auf dem die Dame steht.
	 *            
	 * @param currentPosition
	 *            Position auf der sich die Dame befindet fuer die die moeglichen
	 *            Zuege ermittelt werden sollen.
	 * 
	 * @param step schrittlaenge um die die Figur bewegt werden soll.
	 *                      
	 * @param surveyCheck wenn true, soll nur ueberprueft werde, ob currentPosition ein bedrohtes Feld ist, ohne Boards zu erstellen.
	 * 					  wenn false, sollen neue Zugmoeglichkeiten ermittelt werden.	 
	 * @param colour  Farbe, fuer die die Zugmoeglichkeiten ermittelt werden sollen.
	 * 
	 * 
	 *
	 * @param figure Figur welche gezogen werden soll.
	 * 
	 * @return wenn surveyCheck true ist: true wenn currentPosition bedroht ist.
	 * 									   false wenn currentPosition nicht bedroht ist.
	 * 		   wenn surveyCheck false ist: immer false.		
	 */
	
	private boolean singleMove(Board board,int currentPosition,int step,boolean surveyCheck, int figure) {
		
		boolean check =false;

		int possiblePosition=currentPosition+step;
				
			if (!isIllegalField(board,possiblePosition)&&isEmptyField(board, possiblePosition)){		
				if (surveyCheck) {
					if (isSpecialEnemy(board, figure, possiblePosition)) {
						
						return check=true;
					}else{
						possiblePosition+=step;
					}
				}else{
					
					createBoardObject(board.moveClone(currentPosition, possiblePosition));
					possiblePosition+=step;
					
				}
							
						
			}else{
				if (!isIllegalField(board,possiblePosition)){
					if (!isEmptyField(board, possiblePosition)&& isEnemy(board, currentPosition, possiblePosition)) {
						if (surveyCheck) {
							if (isSpecialEnemy(board, figure, possiblePosition)) {
								
								return check=true;
							}else{
								possiblePosition+=step;
							}
						}else{
							
							createBoardObject(board.moveClone(currentPosition, possiblePosition));
							possiblePosition+=step;
							
						}
					}
				}
				
			}
			return check;
		}
	/**
	 * Diese Funktion berechnet, alle moeglichen Zuege, in eine richtung um die schrittlaenge step auf dem
	 * mitgegebenen Spielbrett unter der angegebenen Position.
	 * 
	 * @param board
	 *            Spielbrett auf dem die Dame steht.
	 *            
	 * @param currentPosition
	 *            Position auf der sich die Dame befindet fuer die die moeglichen
	 *            Zuege ermittelt werden sollen.
	 * 
	 * @param step schrittlaenge um die die Figur bewegt werden soll.
	 *                      
	 * @param surveyCheck wenn true, soll nur ueberprueft werde, ob currentPosition ein bedrohtes Feld ist, ohne Boards zu erstellen.
	 * 					  wenn false, sollen neue Zugmoeglichkeiten ermittelt werden.	 
	 * 
	 * @return wenn surveyCheck true ist: true wenn currentPosition bedroht ist.
	 * 									   false wenn currentPosition nicht bedroht ist.
	 * 		   wenn surveyCheck false ist: immer false.		
	 */	
	/**
	 * @param board
	 * @param currentPosition
	 * @param step
	 * @param surveyCheck
	 * @return
	 */
	private boolean multiMove(Board board, int currentPosition, int step, boolean surveyCheck) {
		boolean colour=board.giveColour(currentPosition);
		boolean stop=false;
		boolean check =false;
		
		int possiblePosition=currentPosition+step;
		int figure1=PieceValues.ILLEGAL_FIELD;
		int figure2=PieceValues.ILLEGAL_FIELD;
		//Dann is es en Turm
		if (Math.abs(step)==1||Math.abs(step)==10) {
			if (colour) {
				figure1=PieceValues.WHITE_ROOK;
				figure2=PieceValues.WHITE_QUEEN;
			}
			if (!colour) {
				figure1=PieceValues.BLACK_ROOK;
				figure2=PieceValues.BLACK_QUEEN;
			}
			
		}
		if (Math.abs(step)==11||Math.abs(step)==9) {
			if (colour) {
				figure1=PieceValues.WHITE_BISHOP;
				figure2=PieceValues.WHITE_QUEEN;
			}
			if (!colour) {
				figure1=PieceValues.BLACK_BISHOP;
				figure2=PieceValues.BLACK_QUEEN;
			}
			
		}
		while (!stop) {	
			if (!isIllegalField(board,possiblePosition)&&isEmptyField(board, possiblePosition)){		
				if (surveyCheck) {
					if ((isSpecialEnemy(board, figure1, possiblePosition))||(isSpecialEnemy(board, figure2, possiblePosition))) {
						
						return check=true;
					}else{
						possiblePosition+=step;
					}
				}else{
					
					createBoardObject(board.moveClone(currentPosition, possiblePosition));
					possiblePosition+=step;
					
				}
						
					
			}else{
				if (!isIllegalField(board,possiblePosition)){
					if (!isEmptyField(board, possiblePosition)&& isEnemy(board, currentPosition, possiblePosition)) {
						if (surveyCheck) {
							if ((isSpecialEnemy(board, figure1, possiblePosition))||(isSpecialEnemy(board, figure2, possiblePosition))) {
								
								return check=true;
							}else{
								possiblePosition+=step;
							}
						}else{
							
							createBoardObject(board.moveClone(currentPosition, possiblePosition));
							possiblePosition+=step;
							
						}
					}
				}
				stop=true;
			}
		}
		return check;
	}

	//-------------------------------Auf Schach pruefen---------------------------------------------
	/**Methode welche den Koenig sucht und prueft ob er von einer gegnerischen Figur bedroht wird.
	 * @param board  Board auf dem der Koenig steht.
	 * @param colour Farbe des Koenigs
	 * @param extern wird die methode ueber die schnittstelle isThreatens auf gerufen
	 * @param positionField feld welches getestet werden soll wenn die Methode extern aufgerufen wird.
	 * @return true wenn der koenig  oder das Feld bedroht wird oder nicht gefunden werden kann.
	 * 		   false wenn der koenig oder das Feld nicht bedroht wird.
	 */
	private boolean isCheck(Board board, boolean colour,boolean extern, int positionField ) {
		
		int king=PieceValues.ILLEGAL_FIELD;
		int pawn=PieceValues.ILLEGAL_FIELD;
		int kingPosition=PieceValues.ILLEGAL_FIELD;
		
		Boolean surveyCheck = true;
		
		//eigenen Koenig suchen.
		
		if (colour) {
			king=PieceValues.WHITE_KING;
		}		
		if (!colour) {
			king=PieceValues.BLACK_KING;
		}		
		if (!extern) {
			kingPosition=findKing(board,king);
			
			if (kingPosition == PieceValues.ILLEGAL_FIELD) {
				//könig nicht gefunden schachmatt!
				return true;
			}
		}else{
			if (positionField==PieceValues.ILLEGAL_FIELD) {
				return true;
			}
			kingPosition=positionField;
		}
		
		//Soeoeoeoe eigener Koenig gefunden! 
		//jetzt gugge ma mol ob der von irgend nem Schlingel bedroht wird und ma die Polizei rufe misse ;)
		
		//Auf gegnerische Dame pruefen un ich daet sahn wo ma grad debei sin ach noch uf Laeufer und Turm^^
		if (moveQueen(board, kingPosition, surveyCheck, colour)) {
			return true;
		}
		//auf gegnerisches Pferd puefen
		if (moveKnight(board, kingPosition, surveyCheck, colour)) {
			return true;
		}
		//pruefen auf generischen Koenig
		if (moveKing(board, kingPosition, surveyCheck, colour)) {
			return true;
		}
		//auf gegnerischen Bauern pruefen
		if (colour) {
			pawn=PieceValues.BLACK_PAWN;
			if ((board.getPiece(kingPosition-9)==pawn)||(board.getPiece(kingPosition-11)==pawn)) {
				return true;
			}
		}		
		if (!colour) {	
			pawn=PieceValues.WHITE_PAWN;
			if ((board.getPiece(kingPosition+9)==pawn)||(board.getPiece(kingPosition+11)==pawn)) {

				return true;
			}
		}	
		
		return false;
			
	}
	//--------------------------Hilfs funktionen-----------------------------------------------
	/**Diese Methode sucht den Koenig auf dem Uebermittelten Board.
	 * @param board	Board auf dem der Koenig gesucht werden soll.
	 * @param king	Wert des Koenigs welcher gesucht werden soll(Schwarz/weiss)
	 * @return		Feld auf dem der gesuchte Koenig steht.
	 * 				wet von ILLEGAL_FIELD wenn der koenig nicht gefunden wird.
	 */
	private int findKing(Board board,int king){
		int kingPosition= PieceValues.ILLEGAL_FIELD;
		int field=21;
		
		while (kingPosition==PieceValues.ILLEGAL_FIELD) {
			if (field<=99) {
				if (board.getPiece(field)==king) {
					//König wurde gefunden die Untertanen freuen sich ^^
					kingPosition=field;
				}
				field++;
			}else{
				//worst case König is nimme do :)
				//daher sahn ma an der stell enfach mol, genau so gudd wie Schach(Matt ;) ) :P
				return PieceValues.ILLEGAL_FIELD;
			}
			
		}
		return kingPosition;
	}
	
	/**Diese Methode prueft ob die Große rochade moeglich waere.
	 * @param currentPosition	Momentane position des Koenigs.
	 * @param board				Board welches getestet werden soll.
	 * @return	true wenn der Rochade moeglich ist.
	 * 			false wenn sie nicht moeglich ist.
	 */
	private boolean isCastQueenSide(int currentPosition,Board board) {
		if (board.getCasQueenside()) {
			if (isEmptyField(board,currentPosition-1)&&isEmptyField(board,currentPosition-2)&&isEmptyField(board,currentPosition-3)) {
				return true;
			}
		}
		return false;
	}
	/**Diese Methode prueft ob die Kleiner rochade moeglich waere.
	 * @param currentPosition	Momentane position des Koenigs.
	 * @param board				Board welches getestet werden soll.
	 * @return	true wenn der Rochade moeglich ist.
	 * 			false wenn sie nicht moeglich ist.
	 */
	private boolean isCastKingSide(int currentPosition,Board board) {
		if (board.getCasKingside()) {
			if (isEmptyField(board,currentPosition+1)&&isEmptyField(board,currentPosition+2)) {
				return true;
			}
		}
		return false;
	}
	/** Diese Methode prueft, ob ein Bauer einen Doppelzug machen darf oer nicht.
	 * @param currentPosition	momentane Position des Bauern.
	 * @return	true wenn der Bauer einen Doppelzug machen darf.
	 * 			false wenn nicht.
	 */
	private  boolean isDoubleMovePossible(int currentPosition) {		
		return (-1!=pawnlist.indexOf(currentPosition));
		
	}
	/** Diese Methode prueft, ob das uebergebene Feld eine Illegales Feld ist.
	 * @param board				Board welches getestet werden soll.
	 * @param currentPosition	Feld welches getesete werden soll.
	 * @return					true wenn es ein Illegales Feld ist.
	 * 							false wenn nicht.
	 */
	private boolean isIllegalField(Board board, int currentPosition) {
		return (board.getPiece(currentPosition) == illegalField);
		
	}
	/**Diese Methode prueft, ob das uebergebene Feld nicht besetzt ist.
	  * @param board				Board welches getestet werden soll.
	 * @param currentPosition	Feld welches getesete werden soll.
	 * @return					true wenn es ein leeres Feld ist.
	 * 							false wenn nicht.
	 */
	private boolean isEmptyField(Board board, int currentPosition) {
		return(board.getPiece(currentPosition) == emptyField);
		
	}
	/** Diese Methode testet ob auf einem bestimmten Feld eine feindliche Figur steht.
	 * @param board				Board welches getestet werden soll.
	 * @param mySelf			Eigene Figur welche schlagen moechte.
	 * @param possibleEnemy		Zu schlagende Figur sofern sie Feindlich ist.
	 * @return					true wenn es ein Gegner ist.
	 * 							false wenn nicht.
	 */
	private boolean isEnemy(Board board, int mySelf,int possibleEnemy) {
		return (board.giveColour(mySelf) != board.giveColour(possibleEnemy));
		
	}
	
	/**
	 * Diese Methode testet ob auf einem bestimmten Feld eine feindliche Figur steht.
	 * 
	 * @param board
	 *            Board welches getestet werden soll.
	 * @param mySelf
	 *            Eigene Figur welche schlagen moechte.
	 * @param possibleEnemy
	 *            Zu schlagende Figur sofern sie Feindlich ist.
	 * @return true wenn es ein Gegner ist. false wenn nicht.
	 */

	private boolean isSpecialEnemy(Board board, int mySelf,int possibleEnemy) {
		return (mySelf == -board.getPiece(possibleEnemy));
		
	}
	/** Diese Methode testet ob das uebergebene Feld ausserhalb 
	 * der linken oder rechten Spielfeldgernze liegt.
	 * 
	 * @param i	zu testendes Feld.
	 * 
	 * @return true wenn das Feld ausserhalb der Grenze liegt.
	 * 		   false wenn nicht.
	 */
	private boolean isOutOfRegularBoard(int i) {
		return (i%10 ==0)||(i%10 ==9);
		
	}


	//----------------------------Main- Wird gelÃ¶scht nur zum testen----------------------------
	
	// TODO Methode nach dem Testen entfernen.
	/**
	 * @param args
	 * @throws BoardException
	 */
	/**
	 * @param args
	 * @throws BoardException
	 */
	public static void main(String[] args) throws BoardException {
		/**
		System.out.println("12="+((2*ONE_FIELD_RIGHT)+ONE_FIELD_AHEAD));
		System.out.println("19="+((2*ONE_FIELD_AHEAD)+ONE_FIELD_LEFT));
		System.out.println("-12="+((ONE_FIELD_LEFT+ONE_FIELD_LEFT)+ONE_FIELD_BACK));
		//berichtigt
		System.out.println("-8="+((2*ONE_FIELD_RIGHT)+ONE_FIELD_BACK));
		
		System.out.println("21="+((2*ONE_FIELD_AHEAD)+ONE_FIELD_RIGHT));
		System.out.println("-21="+((ONE_FIELD_BACK+ONE_FIELD_BACK)+ONE_FIELD_LEFT));
		//berichtigt
		System.out.println("-19="+((2*ONE_FIELD_BACK)+ONE_FIELD_RIGHT));
		*/
		//Board board =  Board.giveDefaultBoard();
		//MoveGenerator h = new MoveGenerator();
		long zstVorher;
		long zstNachher;
		String[] fen = new String[2];
		//fen[0] = "rnbqkbnr/8/8/8/8/8/8/RNBQKBNR w KQkq - 0 1 ";
		 fen[0] = "4K3/8/8/8/8/8/8/5k2 w - QKqk 0 0";
		fen[1] = "";
		Board b = new Board(fen);
		b.move(96, 95);
		//h.generateMove(b, b.isSideWhite());
		//boolean test =h.isThreatens(b, h.whereIsTheKing(b, !b.isSideWhite())+ONE_FIELD_LEFT);
		PieceSquareTableEvaluator piesy = new PieceSquareTableEvaluator();
		
		
		System.out.println(piesy.evaluate(b));
		
		zstVorher = System.currentTimeMillis();
		int boards=0;
		//System.out.println("SOOO jetzt fange ma an mit dem Brett do\n");
		//Board.giveDefaultBoard().toString();
		//System.out.println("un jetzte kumme die berechnete \n");
//		LinkedList<Board> test= null;
//		for (int i = 0; i < 5000; i++) {
//			test=h.generateMove(b, b.isSideWhite());
//			boards+=test.size();
//		}
		zstNachher = System.currentTimeMillis();
		System.out.println(boards+" Boards in " + ((zstNachher - zstVorher)) + " ms erstellt");
		

		
		
		// Aufruf lange dauernder Prozesse
		
		
	  //  System.out.println(test.size());
		// System.out.println("-----------------------------------------------");
		// System.out.println("zug machen bauer von d2 auf d3");
	       // test= h.generateMove(Board.giveDefaultBoard().moveClone(85, 65), b.isSideWhite());

		  ///  test=h.generateMove(b, b.isSideWhite());
		  ///  System.out.println(test.size());
		//h.generateMove(Board.giveDefaultBoard().moveClone(84, 74), true, 0);
//		fen[0] = "rnbkqbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBKQBNR w - QKqk 0 0";
//		fen[1] = "";
//		Board b = new Board(fen);
//		Board bMoved = b.moveClone(85,65);
//
//		LinkedList<Board> test;
//	    test=h.generateMove(bMoved, bMoved.isSideWhite());
//	    System.out.println(test.size());
	}

}


